home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MACD 5
/
MACD 5.bin
/
workbench
/
tools
/
czesc_1
/
cpdist
/
cpdist.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-01-12
|
14KB
|
556 lines
/*
* CPDIST.C
*/
/*
* (c)Copyright 1992-93 by Tobias Ferber.
*
* This file is part of CPDIST.
*
* CPDIST is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation; either version 1 of the License,
* or (at your option) any later version.
*
* CPDIST is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with CPDIST; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "cpdist.h"
#include "filecopy.h"
/* If you don't want CPDIST to interact with the user's keyboard via
* getkey() then you should compile this file with the -DNO_GETKEY option.
* copy_files() (the only function that uses getkey() will then prompt
* waiting for a string instead of a character
*/
#ifndef NO_GETKEY
#include "getkey.h"
#endif
static char rcs_id[]= "$VER: $Id$";
/* scanner modes */
typedef enum { outer_mode, /* reading word seperating chars */
word_mode, /* collecting chars for a word */
string_mode, /* collecting chars for a string */
remark_mode, /* waiting for the end of line */
comment_mode, /* waiting for the matching '*' and '/' */
return_mode, /* word or string complete */
error_mode /* an error occured! return NULL */
} smode_t;
char *getword(FILE *fp)
/* This function will skip everything up to the beginning of the next word
* that is not inside of a comment and then copy the following word into a
* static buffer and terminate it with a '\0' character. A pointer to this
* buffer will be returned.
* A comment is (as in C) everything that stands between a '/' + '*' token
* and the matching '*' + '/'. C++ like comments (named remarks here) are
* also suported. (They begin with two slashes '/' + '/' and end with the
* end of the line they appear in.)
* Note: This file will use lerror() to report error messages to the user.
* If anyone else but this function will read from the given file 'fp' then
* the line numbers reported by lerror() may become wrong! */
{
static char buf[128]; /* should be enough for _one_ word */
static int line= 1; /* line number */
int n=0; /* #of chars in buf[] */
unsigned char c; /* currently read character */
smode_t smode= outer_mode; /* scanner mode */
while(smode!=return_mode && smode!=error_mode && !feof(fp))
{
c= fgetc(fp);
if(feof(fp) && c!=(unsigned char)EOF)
{ echo("In module " __FILE__ ": feof()==TRUE but fgetc()==0x%02x",
(int)(c&0xFF));
c= (unsigned char)EOF;
}
switch(c)
{
case ' ': case '\t': case ':':
switch(smode)
{
case word_mode:
if(c==':') buf[n++]=':';
buf[n++]= '\0';
smode= return_mode;
break;
case string_mode:
buf[n++]= c;
break;
}
break;
case '\n': case '\r':
switch(smode)
{
case word_mode:
buf[n++]= '\0';
smode= return_mode;
break;
case string_mode:
lerror(line,"unterminated string; missing quotes `\"'");
smode= error_mode;
break;
case remark_mode:
smode= outer_mode;
break;
}
line++;
break;
case '\"':
switch(smode)
{
case outer_mode:
smode= string_mode;
break;
case string_mode:
buf[n++]= '\0';
smode= return_mode;
break;
case word_mode:
buf[n++]= '\0';
ungetc(c,fp);
smode= return_mode;
break;
}
break;
case '/':
switch(smode)
{
case outer_mode:
switch(c= fgetc(fp))
{
case '*':
smode= comment_mode;
break;
case '/':
smode= remark_mode;
break;
default:
ungetc(c,fp);
break;
}
break;
case word_mode:
case string_mode:
buf[n++]= c;
break;
}
break;
case '*':
switch(smode)
{
case comment_mode:
switch(c= fgetc(fp))
{
case '/':
smode= outer_mode;
break;
default:
ungetc(c,fp);
break;
}
break;
case word_mode:
case string_mode:
buf[n++]= c;
break;
}
break;
case (unsigned char)EOF:
switch(smode)
{
case word_mode:
buf[n++]= '\0';
smode= return_mode;
break;
case string_mode:
lerror(line,"unterminated string at EOF; closing quotes `\"' missing");
smode= error_mode;
break;
case comment_mode:
lerror(line,"unterminated comment at EOF; closing `*/' missing");
smode= error_mode;
break;
}
break;
default:
switch(smode)
{
case outer_mode:
smode= word_mode;
/* fall through */
case word_mode:
case string_mode:
buf[n++]= c;
break;
}
break;
}
}
buf[n]= '\0'; /* better add one more... */
return (smode==error_mode) ? (char *)0L : buf;
}
typedef struct fnode {
struct fnode *next;
char *fname;
} fnode;
/* collect states */
typedef enum { okay,
no_such_file,
out_of_memory,
syntax_error,
} state_t;
fnode *collect_files(FILE *fp)
/* Here we collect the filenames in the given distfile pointer 'fp' and
* add them to a list of fnode structures. This function reports errors
* (if there are any) via the echo() function (see main.c or so) */
{
char *fname;
fnode *flist = (fnode *)0L,
*last = (fnode *)0L;
int do_collect= 1; /* collect files (1) or skip until next label (0) */
int files= 0; /* #of collected files */
int errors= 0; /* #of syntax errors in distfile */
int black_sheeps= 0; /* #of inaccessable items (e.g. dirs) */
state_t state= okay;
do
{ fname= getword(fp);
if(fname && *fname)
{
if(fname[strlen(fname)-1]==':')
do_collect= ln_member(fname);
else if(do_collect)
{
if(CP_CHECKEXISTS)
{
FILE *tf;
if( tf= fopen(fname,"r") )
fclose(tf);
else
{ perror(fname);
black_sheeps++;
state= no_such_file;
}
}
if(state != no_such_file)
{
fnode *this;
if( this= (fnode *)malloc(sizeof(fnode)) )
{
if( this->fname= (char *)malloc((strlen(fname)+1)*sizeof(char)) )
{
strcpy(this->fname, fname);
this->next= (fnode *)0L;
if(last) last->next= this;
else flist= this;
last= this;
files++;
}
else
{ free(this);
/* this= (fnode *)0L; */
state= out_of_memory;
}
}
else state= out_of_memory;
}
}
}
else if(!feof(fp))
{ errors++;
if(!CP_IGNOREERRORS)
state= syntax_error;
}
if((state==no_such_file) && CP_KEEPGOING)
state= okay;
} while((state==okay) && !feof(fp));
if(state!=okay)
{
/* purge the file list */
while(flist)
{ last= flist;
flist= flist->next;
if(last->fname)
free(last->fname);
free(last);
}
if(state==out_of_memory)
echo("Ran out of memory after having collected %d %s",
files, (files==1) ? "filename" : "filenames");
echo("going down.");
}
if(errors && CP_IGNOREERRORS)
echo("%d %s -- You should revise your Distfile...",
errors, (errors==1) ? "Error" : "Errors");
if(black_sheeps && CP_KEEPGOING)
echo("Couldn't access %d %s",
black_sheeps, (black_sheeps==1) ? "item" : "items");
return flist;
}
#ifdef STRIP_PATHNAMES
char *strfn(char *s)
/* returns the filename w/o leading pathname */
{ char *t;
for(t=s; *s!='\0'; s++)
if(*s==':' || *s=='/' || *s=='\\')
t= &s[1];
return t;
}
#else
#define strfn(s) (s)
#endif /* STRIP_PATHNAMES */
int copy_files(fnode *flist, char *pname)
/* Here we copy all files in 'flist' to the given path 'pname'.
* The destination filename will be generated by concatenation of
* 'pname' and the actual filename in a node of 'flist'. So 'pname'
* must have a trailing slash '/', colon ':' or backslash '\' or
* whatever.
* While copying the files, all nodes in flist will be free()d. */
{
char outname[MAXIMUM_PATHNAME_LENGTH];
char *catpoint;
int numfiles= 0;
long numbytes= 0;
int err= 0;
strcpy(outname, pname);
catpoint= &outname[strlen(outname)];
if(!CP_DRYRUN)
(void)fc_setbuf(global_buffersize);
while(flist && !err)
{
int dothis= 1; /* 1=copy/replace, 0=skip, -1=??? */
fnode *this= flist;
flist= flist->next;
if(this->fname)
{
strcpy(catpoint, strfn(this->fname));
if(!CP_REPLACEALL && !CP_DRYRUN)
{
FILE *fp;
if(fp= fopen(outname,"r"))
{
int key;
fclose(fp);
fprintf(stderr,"%s already exists. replace it? (y/n/a/q) ",outname);
fflush(stderr);
do {
#ifdef NO_GETKEY
char answerbuf[10];
fgets(answerbuf, sizeof(answerbuf), stdin);
key= (int)answerbuf[0];
#else /* !NO_GETKEY */
key= (int)getkey();
#endif /* NO_GETKEY */
switch( key )
{
case 'y': case 'Y':
#ifndef NO_GETKEY
puts("yes");
#endif
dothis= 1;
break;
case 'n': case 'N':
#ifndef NO_GETKEY
puts("no");
#endif
dothis= 0;
break;
case 'a': case 'A':
#ifndef NO_GETKEY
puts("all");
#endif
global_opts |= OPT_REPLACEALL;
dothis= 1;
break;
case 'q': case 'Q':
#ifndef NO_GETKEY
puts("quit");
#endif
dothis= 0;
err= 1; /* positive error codes are not ignored */
break;
default:
dothis= -1; /* hack: means 'invalid choice' */
break;
}
} while( dothis < 0 );
}
}
if(dothis)
{
if(!CP_SILENT)
{
printf( (CP_DRYRUN ? (strchr(outname,' ') ? "\"%s\" " : "%s ")
: " %s"), outname );
fflush(stdout);
}
if(!CP_DRYRUN)
{
long n;
FILE *src, *dst;
if(src= fopen(this->fname,"rb"))
{
if(dst= fopen(outname,"wb"))
{
if( (n= filecopy(src,dst,0L)) < 0L )
{
if(!CP_SILENT)
putchar('\n');
perror( (n==(-1L)) ? this->fname : outname );
echo("Error copying `%s'.",this->fname);
err= n;
}
else
{ numbytes+= n;
if(!CP_SILENT)
{ printf(" (%ld)",n);
fflush(stdout);
}
}
fclose(dst);
}
else
{ if(!CP_SILENT)
putchar('\n');
echo("Can't write to `%s'.",outname);
err= -2L;
}
fclose(src);
}
else
{ if(!CP_SILENT)
putchar('\n');
echo("Can't access input file `%s'.",this->fname);
err= -1L;
}
}
if(!err)
{
++numfiles;
if(!CP_SILENT && !CP_DRYRUN)
putchar('\n');
}
if(CP_SILENT && !CP_DRYRUN)
{ printf("%d %s copied\r",numfiles, (numfiles==1) ? "file" : "files");
fflush(stdout);
}
}
free(this->fname);
}
free(this);
/* Negative error codes indicate I/O errors which are ignored
* if w/ the '--keep-going' option given in the command-line.
* Positive values indicate fatal errors and can be used to
* force exiting from this function */
if(err<0 && CP_KEEPGOING)
err= 0L;
}
if(!CP_DRYRUN)
(void)fc_setbuf(0L);
if(!CP_DRYRUN || (CP_DRYRUN && CP_SILENT))
printf("%d %s%s",numfiles, (numfiles==1) ? "file" : "files",
(CP_DRYRUN) ? ".\n" : " copied.");
if(!CP_DRYRUN)
printf(" (%ld %s)\n", numbytes, (numbytes==1) ? "byte" : "bytes");
return err;
}
int prepare_distribution(char *fname, char *pname)
{
FILE *fp;
int err= 0;
if( fp= fopen(fname,"r") )
{
fnode *flist;
if( flist= collect_files(fp) )
{
err= copy_files(flist, pname);
}
fclose(fp);
}
else
{ perror(fname);
echo("Can't access `%s'\n",fname);
err= 1;
}
return err;
}